View4D_BSR.m 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769
  1. function varargout = View4D_BSR(varargin)
  2. % Viewer for 4D PLS BSRimage .BRIK files.
  3. % - Allows for montages across both slice dimensions and time.
  4. % - Also displays timeseries for selected voxel in BSRimg, GrpAvg or Correlations.
  5. %
  6. % Usage:
  7. % View4D_BRIK(anat_img, brik_img, cellarray_of_condition_groupaverages)
  8. %
  9. % Example:
  10. % View4D_BRIK('anat+tlrc.BRIK', 'functional+tlrc.BRIK', ...
  11. % {'GPAVG_L1_0.5-55Hz_0.040s_1.240s+tlrc.BRIK'; 'GPAVG_RT_0.5-55Hz_0.040s_1.240s+tlrc.BRIK'})
  12. %
  13. % Written by: Natasa Kovacevic
  14. % Modified in areas marked by ** (Nov, 2013: M. Cheung)
  15. % Last modified: Jan. 15, 2014
  16. % Copyright (C) 2013-2014, Natasa Kovacevic
  17. %
  18. % This file is a part of the MEG & PLS Pipeline (MEGPLS). For more
  19. % details, see the documentation included with the software package.
  20. %
  21. % MEGPLS is free software: you can redistribute it and/or modify it under
  22. % the terms of the GNU General Public License version 2 as published by
  23. % the Free Software Foundation. This program is distributed in the hope
  24. % that it will be useful, but WITHOUT ANY WARRANTY; without even the
  25. % implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  26. % See the GNU General Public License for more details.
  27. %
  28. % You should have received a copy of the GNU General Public License along
  29. % with this program. If not, you can download the license here:
  30. % <http://www.gnu.org/licenses/old-licenses/gpl-2.0>.
  31. % NK: note use set/get for fields that come prediscribed with objects (e.g. sliders) and for fields that I added to handles. Use setappdata/getappdata for gui
  32. % Begin initialization code - DO NOT EDIT
  33. gui_Singleton = 0;
  34. gui_State = struct('gui_Name', mfilename, ...
  35. 'gui_Singleton', gui_Singleton, ...
  36. 'gui_OpeningFcn', @View4D_BSR_OpeningFcn, ...
  37. 'gui_OutputFcn', @View4D_BSR_OutputFcn, ...
  38. 'gui_LayoutFcn', [] , ...
  39. 'gui_Callback', []);
  40. if nargin && ischar(varargin{1})
  41. gui_State.gui_Callback = str2func(varargin{1});
  42. end
  43. if nargout
  44. [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
  45. else
  46. gui_mainfcn(gui_State, varargin{:});
  47. end
  48. % End initialization code - DO NOT EDIT
  49. % --- Executes just before View4D_BSR is made visible.
  50. function View4D_BSR_OpeningFcn(hObject, eventdata, handles, varargin)
  51. % This function has no output args, see OutputFcn.
  52. % hObject handle to figure
  53. % eventdata reserved - to be defined in a future version of MATLAB
  54. % handles structure with handles and user data (see GUIDATA)
  55. % varargin command line arguments to View4D_BSR (see VARARGIN)
  56. % Choose default command line output for View4D_BSR
  57. handles.output = hObject;
  58. % Update handles structure
  59. guidata(hObject, handles);
  60. if numel(varargin) < 3 | numel(varargin)>3
  61. disp('You must supply: anatomical underlay, PLS result bootstrap file and cell array of GPAVG files');
  62. disp('All files should be in AFNI format');
  63. disp('Usage: View4D_BSR(anat_img, bsr_img, cellarray_of_condition_groupaverages)');
  64. disp('Example: View4D_BSR(''anat+tlrc.BRIK'', ''PLS_NR500_1grp_L1vsRT_avg_0.040s_1.240s_LV1+tlrc.BRIK'', {''GPAVG_L1_0.5-55Hz_0.040s_1.240s+tlrc.BRIK''; ''GPAVG_RT_0.5-55Hz_0.040s_1.240s+tlrc.BRIK''})');
  65. error('wrong number of inputs ');
  66. end
  67. % load anatomical BRIK file
  68. Opt.format = 'vector';
  69. [err,anat,Info,ErrMessage]=BrikLoad(varargin{1},Opt);
  70. handles.anat = anat;
  71. % load PLS BSR image:
  72. Opt.format = 'vector';
  73. [err,img,Info,ErrMessage]=BrikLoad(varargin{2},Opt);
  74. BSR.img = img;
  75. handles.dims = size(BSR.img); % 4-dimensional (x, y, z, time)
  76. if numel(size(BSR.img))==3, handles.dims(4) = 1; end
  77. handles.BSR = BSR;
  78. handles.Info = Info;
  79. guidata(hObject, handles);
  80. % Sets title to PLS LV info:
  81. %tmp=strfind(Info.HISTORY_NOTE, '***');
  82. % if ~isempty(tmp)
  83. % tmp=Info.HISTORY_NOTE(tmp:end);
  84. % loc=strfind(tmp,'\n');
  85. % finaltmp=tmp(1:(loc(1)-1));
  86. % set(handles.Title,'String',finaltmp);
  87. % else
  88. %** Changed to just display full path of BSRimg as title.
  89. set(handles.Title,'String',varargin{2});
  90. %end
  91. % load condition GPAVG:
  92. for l=1:length(varargin{3})
  93. Opt.format = 'vector';
  94. [err,condimg{l},Info,ErrMessage]=BrikLoad(varargin{3}{l},Opt);
  95. end
  96. handles.condimg = condimg;
  97. handles.gpavgname = varargin{3};
  98. %** set initial clamp range & BSR thresholds:
  99. [~, FuncFileName, ~] = fileparts(varargin{2});
  100. if strcmp(FuncFileName(1:7), 'BSRimg_')
  101. set(handles.TextboxClampRange, 'String', '10');
  102. set(handles.BSR_posthresh, 'String', '3');
  103. set(handles.BSR_negthresh, 'String', '-3');
  104. elseif strcmp(FuncFileName(1:7), 'SALimg_')
  105. set(handles.TextboxClampRange, 'String', '0.01');
  106. set(handles.BSR_posthresh, 'String', '0.001');
  107. set(handles.BSR_negthresh, 'String', '-0.001');
  108. end
  109. % set view and sliders
  110. x = ceil(handles.dims(1)/2);
  111. y = ceil(handles.dims(2)/2);
  112. z = ceil(handles.dims(3)/2);
  113. set(handles.AxialSlider,'Min',1,'Max',handles.dims(3),'SliderStep',[1/(handles.dims(3)-1) 1/(handles.dims(3)-1)],'Value',z);
  114. set(handles.SagitalSlider,'Min',1,'Max',handles.dims(1),'SliderStep',[1/(handles.dims(1)-1) 1/(handles.dims(1)-1)],'Value',x);
  115. set(handles.CoronalSlider,'Min',1,'Max',handles.dims(2),'SliderStep',[1/(handles.dims(2)-1) 1/(handles.dims(2)-1)],'Value',y);
  116. setappdata(handles.Axialview,'slicenum',z);
  117. setappdata(handles.Sagitalview,'slicenum',x);
  118. setappdata(handles.Coronalview,'slicenum',y);
  119. if numel(size(BSR.img))==3
  120. handles.dims(4) = 1;
  121. set(handles.TimeptSlider,'Min',1,'Max',1.001,'SliderStep',[1 1],'Value',1);
  122. else
  123. set(handles.TimeptSlider,'Min',1,'Max',handles.dims(4),'SliderStep',[1/(handles.dims(4)-1) 1/(handles.dims(4)-1)],'Value',1);
  124. end
  125. % set up montage selection listbox and monatge viewing parameters
  126. set(handles.SelectMontage,'String',{'None','Axial','Sagittal','Coronal'});
  127. set(handles.MontageViewingTable,'data',[1 1 handles.dims(1); 1 1 handles.dims(2); 1 1 handles.dims(3); 1 1 3;]);
  128. % start with first timept
  129. set(handles.Timept,'String','1');
  130. % set up bsr, tbsr, blend
  131. UpdateBlend(handles);
  132. % start using gui
  133. UpdateSlices(x,y,z,handles);
  134. UpdateTimept(1,handles);
  135. guidata(hObject, handles); % Update handles structure
  136. function varargout = View4D_BSR_OutputFcn(hObject, eventdata, handles)
  137. varargout{1} = handles.output;
  138. function UpdateBlend(handles)
  139. % set up bsr, tbsr, blend
  140. % this function is normally called only in the begining and when user
  141. % changes bsr thresholds -> because thhreshold is the only thing that
  142. % alters the blend and the colormap
  143. % clamp bsr image for better viewing
  144. %** get clamp range from new textbox:
  145. bsr_clamp = str2num(get(handles.TextboxClampRange, 'String'));
  146. bsr = handles.BSR.img;
  147. bsr(find(bsr>=bsr_clamp)) = bsr_clamp; bsr(find(bsr<=-bsr_clamp)) = -bsr_clamp;
  148. % get bsr threshold
  149. %** Added check to prevent threshold from exceeding max/min of data or clamp
  150. posthresh = str2num(get(handles.BSR_posthresh,'String'));
  151. negthresh = str2num(get(handles.BSR_negthresh,'String'));
  152. maxvalue = getappdata(handles.BSR_posthresh,'d');
  153. minvalue = getappdata(handles.BSR_posthresh,'c');
  154. if posthresh > maxvalue | posthresh <= minvalue
  155. posthresh = maxvalue;
  156. set(handles.BSR_posthresh,'String', posthresh);
  157. end
  158. if negthresh < minvalue | negthresh >= maxvalue
  159. negthresh = minvalue;
  160. set(handles.BSR_negthresh,'String', negthresh);
  161. end
  162. % zero out bsr voxels below threshold
  163. tbsr = bsr;
  164. tbsr(find(tbsr<posthresh & tbsr>negthresh)) = 0;
  165. orig_tbsr = tbsr;
  166. % now map tbsr for colormap
  167. d = max(max(max(max(bsr)))); c = min(min(min(min(bsr))));
  168. if c==d, % that would happen only if tbsr is zero everywhere
  169. tbsr = ones(size(tbsr));
  170. else
  171. tbsr = round(255*(tbsr-c)/(d-c)+1);
  172. end
  173. [cmap, ignore_pts] = set_colormap(d,c,posthresh, negthresh);
  174. colormap(cmap);
  175. % map grayscale image into midwindow in the colormap
  176. img = handles.anat;
  177. a = min(min(min(img)));
  178. b = max(max(max(img)));
  179. img = round(ignore_pts(1) + (ignore_pts(end)-ignore_pts(1))*(img-a)/(b-a));
  180. img = min(max(img,ignore_pts(1)),ignore_pts(end));
  181. img = repmat(img,[1 1 1 handles.dims(4)]);
  182. blend = zeros([size(tbsr) 3]);
  183. for dim=1:3
  184. utmp = reshape(cmap(img,dim),size(tbsr));
  185. otmp = reshape(cmap(tbsr,dim),size(tbsr));
  186. blend(:,:,:,:,dim)= (orig_tbsr==0).* utmp + (orig_tbsr~=0).* otmp;
  187. end
  188. % attach blend and colormap related infor to be used in other gui
  189. % components
  190. setappdata(handles.BSR_posthresh,'blend',blend);
  191. setappdata(handles.BSR_posthresh,'cmap',cmap);
  192. setappdata(handles.BSR_posthresh,'ignore_pts', ignore_pts);
  193. setappdata(handles.BSR_posthresh,'c',c);
  194. setappdata(handles.BSR_posthresh,'d',d);
  195. function UpdateSlices(x,y,z,handles)
  196. % get current bsr thresholds
  197. posthresh = str2num(get(handles.BSR_posthresh,'String'));
  198. negthresh = str2num(get(handles.BSR_negthresh,'String'));
  199. bsr = handles.BSR.img;
  200. % get current time point and make sure that it makes sense
  201. tpt = round(get(handles.TimeptSlider,'value'));
  202. % get blend and colormap
  203. blend_allt= getappdata(handles.BSR_posthresh,'blend');
  204. blend = squeeze(blend_allt(:,:,:,tpt,:));
  205. cmap = getappdata(handles.BSR_posthresh,'cmap');
  206. colormap(cmap);
  207. % AFNI IJK coordinates:
  208. set(handles.Coord,'String',[num2str(x) ' ' num2str(y) ' ' num2str(z)]);
  209. % AFNI indexing convention for AFNI viewer & functions starts at 0.
  210. % Note: AFNI reads orientation in voxel-storage order, so LPI in AFNI is RAS (in spatial direction)
  211. % Recall: RAS is orientation of coordinate space of TLRC and MNI templates.
  212. [err, XYZdic] = AFNI_Index2XYZcontinuous([x-1, y-1, z-1], handles.Info, 'LPI');
  213. set(handles.MNI_coord, 'String', [num2str(XYZdic(1)) ' ' num2str(XYZdic(2)) ' ' num2str(XYZdic(3))]);
  214. % udate slider positions
  215. set(handles.AxialSlider,'Value',z);
  216. set(handles.SagitalSlider,'Value',x);
  217. set(handles.CoronalSlider,'Value',y);
  218. setappdata(handles.Axialview,'slicenum',z);
  219. setappdata(handles.Sagitalview,'slicenum',x);
  220. setappdata(handles.Coronalview,'slicenum',y);
  221. % update slice views
  222. col = [0 0.8 0];
  223. axes(handles.Axialview); % make this current axes
  224. tmp=permute(squeeze(blend(:,:,z,:)),[2 1 3]);
  225. image(tmp,'ButtonDownFcn',{@click_axial,handles});
  226. set(handles.Axialview,'ydir','normal','xtick',[],'ytick',[]);
  227. line([x x],[1 handles.dims(2)],'color',[0 1 0],'visible','on');
  228. line([1 handles.dims(1)],[y y],'color',[0 1 0],'visible','on');
  229. text(2,2,['z=' num2str(z)],'fontsize',12,'fontweight','bold','color',[0 1 0.3]);
  230. axes(handles.Sagitalview); % make this current axes
  231. image(permute(squeeze(blend(x,:,:,:)),[2 1 3]),'ButtonDownFcn',{@click_sagital,handles});
  232. set(handles.Sagitalview,'ydir','normal','xtick',[],'ytick',[]);
  233. line([y y],[1 handles.dims(3)],'color',[0 1 0],'visible','on');
  234. line([1 handles.dims(2)],[z z],'color',[0 1 0],'visible','on');
  235. text(2,2,['x=' num2str(x)],'color','g','fontsize',12,'fontweight','bold');
  236. text(0,handles.dims(3)+2,num2str(bsr(x,y,z,tpt)),'fontsize',12,'fontweight','bold','color','c');
  237. axes(handles.Coronalview); % make this current axes
  238. image(permute(squeeze(blend(:,y,:,:)),[2 1 3]),'ButtonDownFcn',{@click_coronal,handles});
  239. set(handles.Coronalview,'ydir','normal','xtick',[],'ytick',[]);
  240. line([x x],[1 handles.dims(3)],'color',[0 1 0],'visible','on');
  241. line([1 handles.dims(1)],[z z],'color',[0 1 0],'visible','on');
  242. text(2,2,['y=' num2str(y)],'color','g','fontsize',12,'fontweight','bold');
  243. text(0,handles.dims(3)+2,num2str(bsr(x,y,z,tpt)),'fontsize',12,'fontweight','bold','color','m');
  244. % update BSR colorbar
  245. axes(handles.colorbar_view);
  246. imagesc([1:256]'); colormap(cmap);
  247. ignore_pts = getappdata(handles.BSR_posthresh,'ignore_pts');
  248. %** Commented out: Modified below to be more robust accomodating different datasets.
  249. %set(gca, 'ydir', 'normal', 'ytick',[1 ignore_pts(1) ignore_pts(end) 256], 'YTickLabel', {num2str(getappdata(handles.BSR_posthresh,'c')), num2str(negthresh), num2str(posthresh), num2str(getappdata(handles.BSR_posthresh,'d'))}, 'XTickLabel', []);
  250. if ignore_pts(1) <= 1
  251. set(gca, 'ydir', 'normal', 'ytick',[1 ignore_pts(end) 256], 'YTickLabel', {num2str(getappdata(handles.BSR_posthresh,'c')), num2str(posthresh), num2str(getappdata(handles.BSR_posthresh,'d'))}, 'XTickLabel', []);
  252. elseif ignore_pts(end) >= 256
  253. set(gca, 'ydir', 'normal', 'ytick',[1 ignore_pts(1) 256], 'YTickLabel', {num2str(getappdata(handles.BSR_posthresh,'c')), num2str(negthresh), num2str(getappdata(handles.BSR_posthresh,'d'))}, 'XTickLabel', []);
  254. elseif ignore_pts(1) <= 1 && ignore_pts(end) >= 256
  255. set(gca, 'ydir', 'normal', 'ytick',[1 256], 'YTickLabel', {num2str(getappdata(handles.BSR_posthresh,'c')), num2str(getappdata(handles.BSR_posthresh,'d'))}, 'XTickLabel', []);
  256. else
  257. set(gca, 'ydir', 'normal', 'ytick',[1 ignore_pts(1) ignore_pts(end) 256], 'YTickLabel', {num2str(getappdata(handles.BSR_posthresh,'c')), num2str(negthresh), num2str(posthresh), num2str(getappdata(handles.BSR_posthresh,'d'))}, 'XTickLabel', []);
  258. end
  259. % update BSR time series plot
  260. axes(handles.BSR_timeseries);
  261. Tseries = squeeze(handles.BSR.img(x,y,z,:));
  262. if numel(Tseries) > 1
  263. at = min(Tseries); bt = max(Tseries);
  264. num_tpts = numel(Tseries);
  265. tpts = [1:num_tpts];
  266. plot(tpts,Tseries,'b');
  267. hold on;
  268. if bt > at
  269. e = (bt-at)/20;
  270. set(gca,'ylim',[at-e bt+e],'xlim',[0 numel(Tseries)+1]);
  271. else
  272. set(gca,'ylim',[-1 1],'xlim',[0 numel(Tseries)+1]);
  273. end
  274. end
  275. % horizontal dotted red lines indicate bsr thresholds
  276. h=line([1 num_tpts], [posthresh posthresh]);
  277. set(h, 'LineStyle', '--', 'Color', 'r');
  278. h=line([1 num_tpts], [negthresh negthresh]);
  279. set(h, 'LineStyle', '--', 'Color', 'r');
  280. hold off;
  281. title(['BSR = ',num2str(Tseries(tpt))],'color','r','fontsize',14);
  282. minval = min(min(Tseries),negthresh); maxval = max(max(Tseries),posthresh);
  283. E = (maxval - minval)/10;
  284. set(gca,'ylim',[minval-E maxval+E]);
  285. % vertical gray line indicates current tpt
  286. h = line([tpt tpt], [minval-E maxval+E]);
  287. set(h, 'LineStyle', '-', 'Color', [0.6 0.6 0.6]);
  288. set(gca,'ButtonDownFcn',{@click_BSR_ts,handles},'xlim',[0 num_tpts+1]);
  289. setappdata(handles.PrintBSRButton,'bsr_ts',Tseries);
  290. % update group-average condition timeseries plots:
  291. axes(handles.GPAVG_timeseries);
  292. num_GPAVG = length(handles.condimg);
  293. tmparray = zeros(num_GPAVG, length(Tseries));
  294. for l=1:num_GPAVG
  295. tmparray(l,:) = squeeze(handles.condimg{l}(x,y,z,:));
  296. end
  297. tmparray = tmparray';
  298. plot(tmparray); hold on;
  299. for f = 1:length(handles.gpavgname)
  300. [~, File, ~] = fileparts(handles.gpavgname{f});
  301. LegendName{f} = File;
  302. end
  303. clickableLegend(LegendName,'interpreter','none');
  304. YLim = get(gca, 'YLim');
  305. BSRcircleheight = (YLim(2)-((YLim(2)-YLim(1))/10));
  306. circles = find(Tseries > posthresh | Tseries < negthresh);
  307. scatter(circles, BSRcircleheight*ones(size(circles)),'ro');
  308. % vertical gray line indicates current tpt
  309. h = line([tpt tpt], YLim);
  310. set(h, 'LineStyle', '-', 'Color', [0.6 0.6 0.6]);
  311. hold off;
  312. set(gca,'ButtonDownFcn',{@click_GPAVG_ts,handles},'xlim',[0 num_tpts+1]);
  313. setappdata(handles.PrintGPButton,'gpavg_ts',tmparray);
  314. function UpdateTimept(tpt,handles)
  315. % update views
  316. x = getappdata(handles.Sagitalview,'slicenum');
  317. y = getappdata(handles.Coronalview,'slicenum');
  318. z = getappdata(handles.Axialview,'slicenum');
  319. UpdateSlices(x,y,z,handles);
  320. function AxialSlider_Callback(hObject, eventdata, handles)
  321. z = round(get(hObject, 'Value'));
  322. x = round(get(handles.SagitalSlider,'Value'));
  323. y = round(get(handles.CoronalSlider,'Value'));
  324. UpdateSlices(x,y,z,handles);
  325. function SagitalSlider_Callback(hObject, eventdata, handles)
  326. x = round(get(hObject, 'Value'));
  327. z = round(get(handles.AxialSlider,'Value'));
  328. y = round(get(handles.CoronalSlider,'Value'));
  329. UpdateSlices(x,y,z,handles);
  330. function CoronalSlider_Callback(hObject, eventdata, handles)
  331. y = round(get(hObject, 'Value'));
  332. z = round(get(handles.AxialSlider,'Value'));
  333. x = round(get(handles.SagitalSlider,'Value'));
  334. UpdateSlices(x,y,z,handles);
  335. function Timept_Callback(hObject, eventdata, handles)
  336. tpt = round(str2num(get(hObject,'String')));
  337. if tpt<1 || tpt>handles.dims(4)
  338. prompt={
  339. ['Invalid Time.'];
  340. ['Time must be # between: 1 & ',num2str(handles.dims(4))]};
  341. warndlg(prompt,'Warning:','modal');
  342. end
  343. set(handles.TimeptSlider,'Value',tpt);
  344. UpdateTimept(tpt,handles);
  345. function TimeptSlider_Callback(hObject, eventdata, handles)
  346. tpt = round(get(hObject, 'Value'));
  347. set(handles.Timept,'String',num2str(tpt));
  348. UpdateTimept(tpt,handles);
  349. function click_axial(src,eventdata,handles)%callback for buttonclick
  350. c= ginput(1);
  351. x = round(c(1,1));
  352. y = round(c(1,2));
  353. z = getappdata(handles.Axialview,'slicenum');
  354. UpdateSlices(x,y,z,handles);
  355. function click_sagital(src,eventdata,handles)
  356. %c = get(gca,'CurrentPoint');
  357. c= ginput(1);
  358. y = round(c(1,1));
  359. z = round(c(1,2));
  360. x = getappdata(handles.Sagitalview,'slicenum');
  361. UpdateSlices(x,y,z,handles);
  362. function click_coronal(src,eventdata,handles)
  363. %c = get(gca,'CurrentPoint');
  364. c= ginput(1);
  365. x = round(c(1,1));
  366. z = round(c(1,2));
  367. y = getappdata(handles.Coronalview,'slicenum');
  368. UpdateSlices(x,y,z,handles);
  369. function click_BSR_ts(src,eventdata,handles)
  370. c = ginput(1);
  371. tpt = round(c(1));
  372. tpt = min(max(1,tpt), handles.dims(4));
  373. set(handles.Timept,'String',num2str(tpt));
  374. set(handles.TimeptSlider,'value',tpt);
  375. UpdateTimept(tpt,handles);
  376. function click_GPAVG_ts(src,eventdata,handles)
  377. c = ginput(1);
  378. tpt = round(c(1));
  379. tpt = min(max(1,tpt), handles.dims(4));
  380. set(handles.Timept,'String',tpt);
  381. set(handles.TimeptSlider,'value',tpt);
  382. UpdateTimept(tpt,handles);
  383. function Coord_Callback(hObject, eventdata, handles) % user eneters voxel coordinates
  384. coord = round(str2num(get(hObject,'String')));
  385. if (coord(1)<1 || coord(1)>handles.dims(1)) || (coord(2)<1 || coord(2)>handles.dims(2)) || (coord(3)<1 || coord(2)>handles.dims(3))
  386. prompt={
  387. ['Invalid Coordinate.'];
  388. ['X-coord must be # between: 1 & ',num2str(handles.dims(1))];
  389. ['Y-coord must be # between: 1 & ',num2str(handles.dims(2))];
  390. ['Z-coord must be # between: 1 & ',num2str(handles.dims(3))]};
  391. warndlg(prompt,'Warning:','modal');
  392. end
  393. UpdateSlices(coord(1),coord(2),coord(3),handles);
  394. function MNI_coord_Callback(hObject, eventdata, handles)
  395. mni_coord = round(str2num(get(hObject,'String')));
  396. [err, coord] = AFNI_XYZcontinuous2Index(mni_coord, handles.Info, 'LPI', 3);
  397. coord = coord+1; % AFNI indexing convention starts at 0.
  398. UpdateSlices(coord(1),coord(2),coord(3),handles);
  399. function BSR_negthresh_Callback(hObject, eventdata, handles)
  400. thresh = str2num(get(handles.BSR_negthresh,'String'));
  401. if thresh>0, set(handles.BSR_negthresh,'String','0'); end
  402. UpdateBlend(handles);
  403. z = getappdata(handles.Axialview,'slicenum');
  404. x = getappdata(handles.Sagitalview,'slicenum');
  405. y = getappdata(handles.Coronalview,'slicenum');
  406. UpdateSlices(x,y,z,handles);
  407. function BSR_posthresh_Callback(hObject, eventdata, handles)
  408. thresh = str2num(get(handles.BSR_posthresh,'String'));
  409. if thresh<0, set(handles.BSR_posthresh,'String','0'); end
  410. UpdateBlend(handles);
  411. z = getappdata(handles.Axialview,'slicenum');
  412. x = getappdata(handles.Sagitalview,'slicenum');
  413. y = getappdata(handles.Coronalview,'slicenum');
  414. UpdateSlices(x,y,z,handles);
  415. %** Added clamp range textbox
  416. function TextboxClampRange_Callback(hObject, eventdata, handles)
  417. clamp = str2num(get(handles.TextboxClampRange, 'String'));
  418. if clamp<=0, set(handles.TextboxClampRange, 'String', '10'); end
  419. UpdateBlend(handles);
  420. z = getappdata(handles.Axialview,'slicenum');
  421. x = getappdata(handles.Sagitalview,'slicenum');
  422. y = getappdata(handles.Coronalview,'slicenum');
  423. UpdateSlices(x,y,z,handles);
  424. function SelectMontage_Callback(hObject, eventdata, handles)
  425. contents = cellstr(get(hObject,'String')); % get the whole list as a cell array of strings
  426. montage_type = contents{get(hObject,'Value')}; % get current selection
  427. if strmatch(montage_type,{'Axial','Sagittal','Coronal'})
  428. TableData = get(handles.MontageViewingTable,'Data'); % get User defined parmaeters for the montage
  429. figure('NumberTitle','off','name',['Montage ' montage_type]);
  430. dims = handles.dims;
  431. % get blend and subsample according to the montage table parameters
  432. blend = getappdata(handles.BSR_posthresh,'blend');
  433. subblend = blend(TableData(1,1):TableData(1,2):TableData(1,3),TableData(2,1):TableData(2,2):TableData(2,3),TableData(3,1):TableData(3,2):TableData(3,3),TableData(4,1):TableData(4,2):TableData(4,3),:); % (x y z t rgb)
  434. % determine axes permuation order
  435. switch montage_type
  436. case 'Axial', ord = [1 2 3 4]; xlab = 'z slice';
  437. case 'Sagittal', ord = [2 3 1 4]; xlab = 'x slice';
  438. case 'Coronal', ord = [1 3 2 4]; xlab = 'y slice';
  439. end
  440. % permute subblend in awy that is good for the display
  441. subblend = permute(subblend,[ord(2) ord(4) ord(1) ord(3) 5]); % 5th dim is rgb
  442. for d=1:4
  443. span{d} = TableData(ord(d),1):TableData(ord(d),2):TableData(ord(d),3);
  444. end
  445. % determine vertical image size (dim1) and horizontal image size (dim2)
  446. dim1 = numel(span{2}) * numel(span{4}); % rows = ysize*time
  447. dim2 = numel(span{1}) * numel(span{3}); % columns = xsize*zsize
  448. % reshape subblend and show
  449. subblend = reshape(subblend,dim1,dim2,3);
  450. image(subblend,'ButtonDownFcn',{@click_Montage,handles});
  451. set(gca,'ydir','normal','xtick',([1:numel(span{3})]-0.5)*numel(span{1}),'xticklabel',cellstr(int2str(span{3}'))','ytick',([1:numel(span{4})]-0.5)*numel(span{2}),'yticklabel',cellstr(int2str(span{4}'))');
  452. ylabel('Time');
  453. xlabel(xlab);
  454. % get current gui (x y z t) coordinate
  455. z = getappdata(handles.Axialview,'slicenum');
  456. x = getappdata(handles.Sagitalview,'slicenum');
  457. y = getappdata(handles.Coronalview,'slicenum');
  458. t = round(get(handles.TimeptSlider,'value'));
  459. coord = [x y z t];
  460. % tranaslate this coordinate into this image space
  461. for d=1:4, subcoord(d) = round((coord(d)-TableData(d,1))/TableData(d,2))+1; end
  462. subcoord = subcoord(ord);
  463. % plot crosshair and
  464. horpos = numel(span{2})*(subcoord(4)-1) + subcoord(2);
  465. verpos = numel(span{1})*(subcoord(3)-1) + subcoord(1);
  466. horline = line([1 dim2],[horpos horpos],'color',[0 1 0],'visible','on');
  467. verline = line([verpos verpos],[1 dim1],'color',[0 1 0],'visible','on');
  468. % record current montage window settings
  469. setappdata(handles.MontageViewingTable,'span',span);
  470. setappdata(handles.MontageViewingTable,'ord',ord);
  471. setappdata(handles.MontageViewingTable,'subcoord',subcoord);
  472. setappdata(handles.MontageViewingTable,'fig',gcf);
  473. setappdata(handles.MontageViewingTable,'horline',horline);
  474. setappdata(handles.MontageViewingTable,'verline',verline);
  475. setappdata(handles.MontageViewingTable,'horpos',horpos);
  476. setappdata(handles.MontageViewingTable,'verpos',verpos);
  477. end
  478. function click_Montage(src,eventdata,handles)%callback for buttonclick
  479. % % when user click on the montage figure reverse the caluclation from SelectMontage_Callbac
  480. % % to obtain [x y z t] in the original image space
  481. % c = ginput(1);
  482. % horpos = round(c(1,1));
  483. % verpos = round(c(1,2));
  484. % rspan = getappdata(handles.MontageViewingTable,'span');
  485. % ord = getappdata(handles.MontageViewingTable,'ord');
  486. % TableData = get(handles.MontageViewingTable,'Data'); % get User defined parmaeters for the montage
  487. % revord(ord) = [1:4]; % reverse order; this statement defines new variable revord
  488. % for d=1:4, span{d} = rspan{revord(d)}; end
  489. % subcoord(2) = mod(horpos,numel(span{2}));
  490. % subcoord(4) = (horpos - subcoord(2))/numel(span{2})+1;
  491. % subcoord(1) = mod(verpos,numel(span{1}));
  492. % subcoord(3) = (verpos - subcoord(1))/numel(span{1})+1;
  493. % revord(ord) = [1:4]; % reverse order; this statement defines new variable revord
  494. % subcoord
  495. % ord
  496. % revord
  497. % %subcoord = subcoord(revord)
  498. % for d=1:4,
  499. % coord(d) = round( (subcoord(d)-1)*TableData(d,2) + TableData(d,1) );
  500. % coord(d) = min(max(1,coord(d)),handles.dims(d));
  501. % end
  502. % set(handles.Timept,'String',num2str(coord(4)));
  503. % set(handles.TimeptSlider,'value',coord(4));
  504. %
  505. % % redraw crosshairs
  506. % dim1 = numel(span{2}) * numel(span{4}); % rows = ysize*time
  507. % dim2 = numel(span{1}) * numel(span{3}); % columns = xsize*zsize
  508. % horline = getappdata(handles.MontageViewingTable,'horline');
  509. % verline = getappdata(handles.MontageViewingTable,'verline');
  510. % set(horline,'visible','off');set(verline,'visible','off');
  511. % figure(getappdata(handles.MontageViewingTable,'fig'));
  512. % horline = line([1 dim2],[horpos horpos],'color',[0 1 0],'visible','on');
  513. % verline = line([verpos verpos],[1 dim1],'color',[0 1 0],'visible','on');
  514. % setappdata(handles.MontageViewingTable,'horline',horline);
  515. % setappdata(handles.MontageViewingTable,'verline',verline);
  516. % setappdata(handles.Sagitalview,'slicenum',coord(1));
  517. % setappdata(handles.Coronalview,'slicenum',coord(2));
  518. % setappdata(handles.Axialview,'slicenum',coord(3));
  519. % set(handles.Timept,'String',num2str(coord(4)));
  520. % set(handles.TimeptSlider,'value',coord(4));
  521. % UpdateTimept(coord(4),handles);
  522. function PrintGPButton_Callback(hObject, eventdata, handles)
  523. val = get(hObject,'Value');
  524. if val==1
  525. gpavg_ts = getappdata(handles.PrintGPButton,'gpavg_ts')
  526. set(hObject,'Value',0);
  527. end
  528. function PrintBSRButton_Callback(hObject, eventdata, handles)
  529. val = get(hObject,'Value');
  530. if val==1
  531. bsr_ts = getappdata(handles.PrintBSRButton,'bsr_ts')
  532. set(hObject,'Value',0);
  533. end
  534. function MontageViewingTable_CellEditCallback(hObject, eventdata, handles)
  535. val = round(str2num(eventdata.EditData)); % get cell content as entered by user
  536. inds = eventdata.Indices; % find (i,j) position in the table
  537. % if new value is outside of alowable dims, then change back to previous
  538. % cell content
  539. if ~(val >=1 & val <= handles.dims(inds(1)))
  540. TableData = get(handles.MontageViewingTable,'Data');
  541. TableData(inds(1),inds(2)) = eventdata.PreviousData;
  542. set(handles.MontageViewingTable,'Data',TableData);
  543. end
  544. function MontageViewingTable_CellSelectionCallback(hObject, eventdata, handles)
  545. % hObject handle to MontageViewingTable (see GCBO)
  546. % eventdata structure with the following fields (see UITABLE)
  547. % Indices: row and column indices of the cell(s) currently selecteds
  548. % handles structure with handles and user data (see GUIDATA)
  549. % NK: note we must have this function even if it doesn't do anything!!!!!
  550. function [cmap,ignore_pts] = set_colormap(max_bsr, min_bsr, pos_bsr_thresh, neg_bsr_thresh)
  551. % written by Jimmy - NK made some changes
  552. % set the display colormap based on the max/min display values and
  553. % the threshold setting.
  554. %
  555. % The upper colors are coming from the entries of [140:239] of the
  556. % 255 jet colormap, and the lower colors are from the entries of
  557. % [1:100] of the colormap.
  558. %
  559. range_interval = max_bsr - min_bsr;
  560. upper_interval = max_bsr - pos_bsr_thresh;
  561. lower_interval = neg_bsr_thresh - min_bsr; % abs(min_bsr) - abs(neg_bsr_thresh);
  562. % colormap entries for the upper range values, using the
  563. % entries of [140:239] from the 255 jet colormap
  564. %
  565. num_upper_colors = 0;
  566. if (upper_interval > 0)
  567. num_upper_colors = round(upper_interval / range_interval * 255);
  568. cmap_size = round(255 * num_upper_colors/100);
  569. first_color_idx = round(140 / 255 * cmap_size);
  570. last_color_idx = first_color_idx + num_upper_colors - 1;
  571. uppermap = jet(cmap_size);
  572. upper_colors = uppermap(first_color_idx:last_color_idx,:);
  573. end;
  574. % colormap entries for the lower range values, using the
  575. % entries of [1:100] from the 255 jet colormap
  576. %
  577. num_lower_colors = 0;
  578. if (lower_interval > 0)
  579. num_lower_colors = round(lower_interval / range_interval * 255);
  580. cmap_size = round(255 * num_lower_colors/100);
  581. first_color_idx = 1;
  582. last_color_idx = num_lower_colors;
  583. lowermap = jet(cmap_size);
  584. lower_colors = lowermap(first_color_idx:last_color_idx,:);
  585. end;
  586. cmap = zeros(256,3);
  587. cmap(1:255,:) = jet(255);
  588. ignore_pts = [(num_lower_colors+1):(255-num_upper_colors)];
  589. if (num_lower_colors > 0),
  590. cmap(1:num_lower_colors,:) = lower_colors;
  591. end;
  592. if (num_upper_colors > 0),
  593. if ~isempty(ignore_pts)
  594. cmap((ignore_pts(end)+1):255,:) = upper_colors;
  595. else
  596. cmap((255-num_upper_colors+1):255,:) = upper_colors;
  597. end
  598. end
  599. if ~isempty(ignore_pts)
  600. %cmap(ignore_pts,:) = ones(length(ignore_pts),3) * 140/255;
  601. cmap(ignore_pts,:) = gray(numel(ignore_pts));
  602. end
  603. cmap(256,:) = [1 1 1];
  604. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  605. %%%%%%%%% Create functions
  606. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  607. function BSR_posthresh_CreateFcn(hObject, eventdata, handles)
  608. if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
  609. set(hObject,'BackgroundColor','white');
  610. end
  611. function BSR_negthresh_CreateFcn(hObject, eventdata, handles)
  612. if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
  613. set(hObject,'BackgroundColor','white');
  614. end
  615. function MNI_coord_CreateFcn(hObject, eventdata, handles)
  616. if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
  617. set(hObject,'BackgroundColor','white');
  618. end
  619. function Coord_CreateFcn(hObject, eventdata, handles)
  620. if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
  621. set(hObject,'BackgroundColor','white');
  622. end
  623. function TimeptSlider_CreateFcn(hObject, eventdata, handles)
  624. if isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
  625. set(hObject,'BackgroundColor',[.9 .9 .9]);
  626. end
  627. function Timept_CreateFcn(hObject, eventdata, handles)
  628. if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
  629. set(hObject,'BackgroundColor','white');
  630. end
  631. function CoronalSlider_CreateFcn(hObject, eventdata, handles)
  632. if isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
  633. set(hObject,'BackgroundColor',[.9 .9 .9]);
  634. end
  635. function SagitalSlider_CreateFcn(hObject, eventdata, handles)
  636. if isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
  637. set(hObject,'BackgroundColor',[.9 .9 .9]);
  638. end
  639. function AxialSlider_CreateFcn(hObject, eventdata, handles)
  640. if isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
  641. set(hObject,'BackgroundColor',[.9 .9 .9]);
  642. end
  643. function SelectMontage_CreateFcn(hObject, eventdata, handles)
  644. if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
  645. set(hObject,'BackgroundColor','white');
  646. end
  647. %** Added clamp range textbox
  648. % --- Executes during object creation, after setting all properties.
  649. function TextboxClampRange_CreateFcn(hObject, eventdata, handles)
  650. if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
  651. set(hObject,'BackgroundColor','white');
  652. end